Connection and Endpoint Types

  1. Introduction
  2. Connection Types
  3. Parameterized Connection Types
  4. Endpoint Types
  5. Parameterized Endpoint Types
  6. Reapplying Types
  7. Fluid Interface

Introduction

A Type is a collection of attributes such as paint style, hover paint style, overlays etc - it is a subset, including most but not all, of the parameters you can set in an Endpoint or Connection definition. It also covers behavioural attributes such as isSource or maxConnections on Endpoints.

An Endpoint or Connection can have zero or more Types assigned; they are merged as granularly as possible, in the order in which they were assigned. There is a supporting API that works in the same way as the class stuff does in jQuery:

and each of these methods (except hasType) takes a space-separated string so you can add several at once. Support for these methods has been added to the jsPlumb.select and jsPlumb.selectEndpoint methods, and you can also now specify a type parameter to an Endpoint or Connection at create time.

Types are a useful tool when you are building a UI that has connections whose appearance change under certain circumstances, or a UI that has various types of connections etc.

Connection Type

Probably the easiest way to explain Types is with some code. In this snippet, we'll register a Connection Type on jsPlumb, create a Connection, and then assign the Type to it:

jsPlumb.registerConnectionType("example", {
    paintStyle:{ strokeStyle:"blue", lineWidth:5  },
    hoverPaintStyle:{ strokeStyle:"red", lineWidth:7 }
});

var c = jsPlumb.connect({ source:"someDiv", target:"someOtherDiv" });
c.bind("click", function() {
    c.setType("example");
});    

Another example - a better one, in fact. Say you have a UI in which you can click to select or deselect Connections, and you want a different appearance for each state. Connection Types to the rescue!

jsPlumb.registerConnectionTypes({
    "basic": {
        paintStyle:{ strokeStyle:"blue", lineWidth:5  },
        hoverPaintStyle:{ strokeStyle:"red", lineWidth:7 }
    },
    "selected":{
        paintStyle:{ strokeStyle:"red", lineWidth:5 },
        hoverPaintStyle:{ lineWidth: 7 }
    }    
});

var c = jsPlumb.connect({ source:"someDiv", target:"someOtherDiv", type:"basic" });

c.bind("click", function() {
    c.toggleType("selected");
});    

Notice here how we used a different method -registerConnectionTypes - to register a few Types at once.

Notice also the hoverPaintStyle for the selected Type: it declares only a lineWidth. As mentioned above, Types are merged with as much granularity as possible, so that means that in this case the lineWidth value from selected will be merged into the hoverPaintStyle from basic, and voila, red, 7 pixels.

These examples, of course, use the jsPlumb.connect method, but in many UIs Connections are created via drag and drop. How would you assign that basic Type to a Connection created with drag and drop? You provide it as the Endpoint's connectorType parameter, like so:

var e1 = jsPlumb.addEndpoint("someDiv", {
    connectorType:"basic",
    isSource:true
});    

var e2 = jsPlumb.addEndpoint("someOtherDiv", {
    isTarget:true
});

//... user then perhaps drags a connection...or we do it programmatically:

var c = jsPlumb.connect({ source:e1, target:e2 });

// now c has type 'basic'
console.log(c.hasType("basic));   // -> true

Note that the second Endpoint we created did not have a connectorType parameter - we didn't need it, as the source Endpoint in the Connection had one. But we could have supplied one, and jsPlumb will use it, but only if the source Endpoint has not declared connectorType. This is the same way jsPlumb treats other Connector parameters such as paintStyle etc - the source Endpoint wins.

Supported Parameters in Connection Type objects

Not every parameter from a Connection's constructor is supported in a Connection Type - as mentioned above, Types act pretty much like CSS classes, so the things that are supported are related to behaviour or appearance. For instance, source is not supported: it indicates the source element for some particular Connection and therefore does not make sense inside a type specification: you cannot make a Connection Type that is fixed to a specific source element. Here's the full list of supported properties in Connection Type objects:

Parameterized Connection Types

Connection Types support parameterized values - values that are derived at runtime by some object you supply. Here's the first example from above, with a parameterized value for strokeStyle:

jsPlumb.registerConnectionType("example", {
    paintStyle:{ strokeStyle:"${color}", lineWidth:5  },
    hoverPaintStyle:{ strokeStyle:"red", lineWidth:7 }
});

var c = jsPlumb.connect({ source:"someDiv", target:"someOtherDiv" });
c.bind("click", function() {
    c.setType("example", { color:"blue" });
});    

setType, addType and toggleType all now support this optional second argument.

You can also use a parameterized Type in a jsPlumb.connect call, by supplying a data value:

jsPlumb.registerConnectionType("example", {
    paintStyle:{ strokeStyle:"${color}", lineWidth:5  },
    hoverPaintStyle:{ strokeStyle:"red", lineWidth:7 }
});

var c = jsPlumb.connect({ 
    source:"someDiv", 
    target:"someOtherDiv",
    type:"example",
    data:{ color: "blue" }
});

Here are a few examples showing you the full Type API:

jsPlumb.registerConnectionTypes({
  "foo":{ paintStyle:{ strokeStyle:"yellow", lineWidth:5 } },
  "bar":{ paintStyle:{ strokeStyle:"blue", lineWidth:10 } },
  "baz":{ paintStyle:{ strokeStyle:"green", lineWidth:1 } },
  "boz":{ paintStyle: { strokeStyle:"${color}", lineWidth:"${width}" } }
});

var c = jsPlumb.connect({ 
  source:"someDiv", 
  target:"someOtherDiv", 
  type:"foo" 
});

// see what types the connection has.  
console.log(c.hasType("foo"));  // -> true
console.log(c.hasType("bar"));  // -> false

// add type 'bar'
c.addType("bar");

// toggle both types (they will be removed in this case)
c.toggleType("foo bar");

// toggle them back
c.toggleType("foo bar");

// getType returns a list of current types.
console.log(c.getType()); // -> [ "foo", "bar" ]

// set type to be 'baz' only
c.setType("baz");

// add foo and bar back in
c.addType("foo bar");

// remove baz and bar
c.removeType("baz bar");

// what are we left with? good old foo.
console.log(c.getType()); // -> [ "foo" ]

// now let's add 'boz', a parameterized type
c.addType("boz", {
  color:"#456",
    width:35
});

Things to note here are that every method except hasType can take a space-delimited list of Types to work with. So types work like CSS classes, basically. I think I might have mentioned that already though.

Endpoint Type

Endpoints can also be assigned one or more Types, both at creation and programmatically using the API discussed above.

The only real differences between Endpoint and Connection Types are the allowed parameters. Here's the list for Endpoints:

One thing to be aware of is that the parameters here that are passed to Connections are only passed from a source Endpoint, not targets. Here's an example of using Endpoint Types:

jsPlumb.registerEndpointTypes({
  "basic":{            
    paintStyle:{fillStyle:"blue"}
  },
  "selected":{            
    paintStyle:{fillStyle:"red"}
  }
});

var e = jsPlumb.addEndpoint("someElement", {
  anchor:"TopMiddle",
    type:"basic"
});

e.bind("click", function() {
  e.toggleType("selected");
});

So it works the same way as Connection Types. There are several parameters allowed by an Endpoint Type that affect Connections coming from that Endpoint. Note that this does not affect existing Connections. It affects only Connections that are created after you set the new Type(s) on an Endpoint.

Parameterized Endpoint Types

You can use parameterized Types for Endpoints just as you can Connections:

jsPlumb.registerEndpointType("example", {
    paintStyle:{ fillStyle:"${color}"}
});

var e = jsPlumb.addEndpoint("someDiv", { 
    type:"example",
    data:{ color: "blue" }
});

Reapplying Types

If you have one or more parameterized Types set on some object and you wish for them to change to reflect a change in their underlying data, you can use the reapplyTypes function:

jsPlumb.registerConnectionStyle("boz",{ 
  paintStyle: { 
    strokeStyle:"${color}", 
    lineWidth:"${width}" 
  } 
}
var c = jsPlumb.connect({ source:"s", target:"t" });
c.addType("boz",{ color:"green", width:23 });

.. things happen ..

c.reapplyTypes({ color:"red", width:0 });

reapplyTypes applies the new parameters to the merged result of all Types currently set on an object.

Fluid Interface

As mentioned previously, all of the Type operations are supported by the select and selectEndpoints methods.

So you can do things like this:

jsPlumb.selectEndpoints({
  scope:"terminal"
}).toggleType("active");

jsPlumb.select({
  source:"someElement"
}).addType("highlighted available");    

Obviously, in these examples, available and highlighted would have previously been registered on jsPlumb using the appropriate register methods.